﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using ProjectEuler.Extensions;

namespace ProjectEuler.Problems
{
    [EulerProblem(79, "73162890")]
    [Description("By analysing a user's login attempts, can you determine the secret numeric passcode?")]
    internal sealed class Problem079 : EulerProblem
    {
        public override Object Solve()
        {
            var pin = new List<Int32>();
            var lines = new String[0];

            using (var reader = OpenTextAttachment())
            {
                lines = reader.ReadAllLines().Where(l => l.Length > 0).ToArray();
            }

            foreach (var line in lines)
            {
                AddNumberToPin(pin, line.ToCharArray().Select(ch => ch - '0').ToArray());
            }

            return String.Join(String.Empty, pin.Select(n => n.ToString()).ToArray());
        }

        private void AddNumberToPin(List<Int32> pin, Int32[] digits)
        {
            pin.AddRange(digits.Where(d => !pin.Contains(d)));

            for (var di = 1; di < digits.Length - 1; di++)
            {
                EnsureXAfterY(pin, digits[di + 1], digits[di]);
                EnsureXAfterY(pin, digits[di], digits[di - 1]);
            }
        }

        private void EnsureXAfterY(List<Int32> pin, Int32 x, Int32 y)
        {
            var ix = pin.IndexOf(x);
            var iy = pin.IndexOf(y);

            if (ix < 0)
            {
                if (iy < 0)
                {
                    pin.Add(y);
                    pin.Add(x);
                }
                else
                {
                    pin.Insert(iy + 1, x);
                }
            }
            else
            {
                if (ix < iy)
                {
                    pin.RemoveAt(ix);
                    pin.Insert(iy, x);
                }
            }
        }
    }
}
